The mechanism that lets a single-threaded language never actually block.
JavaScript runs on a single call stack, but it doesn't block waiting for slow things like network requests or timers, because the language itself never handles them — the runtime environment (a browser or Node.js) does. When you call setTimeout or fetch, the runtime takes over that work outside the JS engine, and once it's done, the corresponding callback is queued up to run later. The event loop's entire job is to check: is the call stack empty? If so, pull the next queued piece of work and run it.
What confuses most people is that the queue isn't singular. Promise callbacks land in the microtask queue, which the event loop always drains completely before touching the macrotask queue that setTimeout, setInterval, and I/O callbacks live in. That ordering — call stack, then all microtasks, then one macrotask, repeat — is why a Promise.resolve().then() reliably fires before a setTimeout(fn, 0), even though both look 'immediate' on paper.
What you'll walk away knowing